#include "btns.c"
#include "lcd12864.c"
#include "uart.c"
#include "timer.c"

#define POS_RIGHT 1
#define POS_UP 2
#define POS_LEFT 3
#define POS_DOWN 4

#define TYPE_INDEX_BLOCK 0
#define TYPE_INDEX_HEAD_RIGHT 1
#define TYPE_INDEX_HEAD_UP 2
#define TYPE_INDEX_HEAD_LEFT 3
#define TYPE_INDEX_HEAD_DOWN 4
#define TYPE_INDEX_BODY_RIGHT_UP 5
#define TYPE_INDEX_BODY_LEFT_RIGHT 6
#define TYPE_INDEX_BODY_RIGHT_DOWN 7
#define TYPE_INDEX_BODY_LEFT_UP 8
#define TYPE_INDEX_BODY_UP_DOWN 9
#define TYPE_INDEX_BODY_LEFT_DOWN 10
#define TYPE_INDEX_TAIL_LEFT 11
#define TYPE_INDEX_TAIL_DOWN 12
#define TYPE_INDEX_TAIL_RIGHT 13
#define TYPE_INDEX_TAIL_UP 14
#define TYPE_INDEX_FOOT 15

#define STATE_START 0
#define STATE_PLAYING 1
#define STATE_GAME_OVER 2

unsigned char code SHAPE_TYPE[][8] = {
    0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // 实心，0
    0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0x5A, 0x3C, 0x18, // 蛇头方向，右，1
    0x38, 0x7C, 0xFA, 0xFF, 0xFF, 0xFA, 0x7C, 0x38, // 蛇头方向，上，2
    0x18, 0x3C, 0x5A, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, // 蛇头方向，左，3
    0x1C, 0x3E, 0x5F, 0xFF, 0xFF, 0x5F, 0x3E, 0x1C, // 蛇头方向，下，4
    0x00, 0x7E, 0x7F, 0x67, 0x67, 0x7F, 0x7E, 0x3C, // 蛇身连接，右上，5
    0x3C, 0x7E, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x3C, // 蛇身连接，右左，6
    0x00, 0x7E, 0xFE, 0xE6, 0xE6, 0xFE, 0x7E, 0x3C, // 蛇身连接，右下，7
    0x3C, 0x7E, 0x7F, 0x67, 0x67, 0x7F, 0x7E, 0x00, // 蛇身连接，上左，8
    0x00, 0x7E, 0xFF, 0xE7, 0xE7, 0xFF, 0x7E, 0x00, // 蛇身连接，上下，9
    0x3C, 0x7E, 0xFE, 0xE6, 0xE6, 0xFE, 0x7E, 0x00, // 蛇身连接，左下，10
    0x3C, 0x7E, 0x7E, 0x3C, 0x3C, 0x18, 0x18, 0x00, // 蛇尾方向，左，11
    0x00, 0x60, 0xF8, 0xFE, 0xFE, 0xF8, 0x60, 0x00, // 蛇尾方向，下，12
    0x00, 0x18, 0x18, 0x3C, 0x3C, 0x7E, 0x7E, 0x3C, // 蛇尾方向，右，13
    0x00, 0x06, 0x1F, 0x7F, 0x7F, 0x1F, 0x06, 0x00, // 蛇尾方向，上，14
    0x00, 0x7E, 0x42, 0x5A, 0x5A, 0x42, 0x7E, 0x00, // 食物，15
};

// 硬件烧录的时候，要看这里大小，data不能超过SNAKE_BODY_MAX
unsigned char idata snake_body[50] = {0};

#define SNAKE_BODY_MAX (sizeof(snake_body) / sizeof(snake_body[0]))

unsigned char snake_head;
unsigned char snake_length;
unsigned char current_direction = POS_RIGHT;
unsigned char last_direction = POS_RIGHT;
unsigned char game_over_flag = 0;
unsigned char game_state = STATE_START;
unsigned char food_position;
unsigned int score = 0;
unsigned int speed = 1;  // 初始速度
unsigned int timer_count = 0;

/**
 * 相对于ref，target在ref的上、下、左、右 哪个方位
 *
 * @return 方向标识:
 *   1 - target在ref的右侧
 *   2 - target在ref的上方
 *   3 - target在ref的左侧
 *   4 - target在ref的下方
 */
unsigned char get_relative_direction(unsigned char ref, unsigned char target)
{
    char dx = (target / 16) - (ref / 16); // 列差
    char dy = (target % 16) - (ref % 16); // 行差
    if (dx > 0)
        return POS_RIGHT;
    if (dx < 0)
        return POS_LEFT;
    if (dy > 0)
        return POS_DOWN;
    return POS_UP;
}

// 获取位置显示类型
unsigned char get_shape_type_index(unsigned char body_part)
{
    unsigned char tail_idx;
    unsigned char i;

    // 蛇头位置
    if (body_part == snake_body[snake_head])
    {
        return current_direction; // 1-4 对应蛇头方向
    }

    // 蛇尾位置
    tail_idx = (snake_head + SNAKE_BODY_MAX - snake_length + 1) % SNAKE_BODY_MAX;
    if (body_part == snake_body[tail_idx])
    {
        // 确保至少有2节才计算方向（包括头尾）
        if (snake_length > 1)
        {
            unsigned char tail_front = (tail_idx + 1) % SNAKE_BODY_MAX;
            unsigned char tail_direction = get_relative_direction(snake_body[tail_idx], snake_body[tail_front]);
            if (tail_direction == POS_RIGHT)
                return TYPE_INDEX_TAIL_RIGHT; // 右 → 13
            else if (tail_direction == POS_UP)
                return TYPE_INDEX_TAIL_UP; // 上 → 14
            else if (tail_direction == POS_LEFT)
                return TYPE_INDEX_TAIL_LEFT; // 左 → 11
            else if (tail_direction == POS_DOWN)
                return TYPE_INDEX_TAIL_DOWN; // 下 → 12
        }
        return TYPE_INDEX_TAIL_LEFT;
    }

    // 蛇身位置
    for (i = 1; i < snake_length - 1; i++)
    {
        unsigned char idx = (snake_head + SNAKE_BODY_MAX - i) % SNAKE_BODY_MAX;
        if (body_part == snake_body[idx])
        {
            // 靠近头部
            unsigned char front = snake_body[(idx + 1) % SNAKE_BODY_MAX];
            // 靠近尾部
            unsigned char back = snake_body[(idx + SNAKE_BODY_MAX - 1) % SNAKE_BODY_MAX];
            unsigned char direction_to_front = get_relative_direction(body_part, front);
            unsigned char direction_to_back = get_relative_direction(body_part, back);
            if (direction_to_front == direction_to_back)
            {
                return (direction_to_front == POS_RIGHT || direction_to_front == POS_LEFT) ? 6 : 9;
            }
            if ((direction_to_front == POS_RIGHT && direction_to_back == POS_LEFT) || (direction_to_front == POS_LEFT && direction_to_back == POS_RIGHT))
                return TYPE_INDEX_BODY_LEFT_RIGHT;
            if ((direction_to_front == POS_UP && direction_to_back == POS_DOWN) || (direction_to_front == POS_DOWN && direction_to_back == POS_UP))
                return TYPE_INDEX_BODY_UP_DOWN;
            if ((direction_to_front == POS_RIGHT && direction_to_back == POS_UP) || (direction_to_front == POS_UP && direction_to_back == POS_RIGHT))
                return TYPE_INDEX_BODY_RIGHT_UP;
            if ((direction_to_front == POS_RIGHT && direction_to_back == POS_DOWN) || (direction_to_front == POS_DOWN && direction_to_back == POS_RIGHT))
                return TYPE_INDEX_BODY_RIGHT_DOWN;
            if ((direction_to_front == POS_UP && direction_to_back == POS_LEFT) || (direction_to_front == POS_LEFT && direction_to_back == POS_UP))
                return TYPE_INDEX_BODY_LEFT_UP;
            if ((direction_to_front == POS_LEFT && direction_to_back == POS_DOWN) || (direction_to_front == POS_DOWN && direction_to_back == POS_LEFT))
                return TYPE_INDEX_BODY_LEFT_DOWN;
            return TYPE_INDEX_BLOCK;
        }
    }

    return TYPE_INDEX_BLOCK; // 空位置
}

// 移动蛇
void move_snake()
{
    unsigned char new_body;
    unsigned char i;

    // 计算新位置
    switch (current_direction)
    {
    case POS_RIGHT:
        new_body = snake_body[snake_head] + 16;
        break;
    case POS_UP:
        new_body = snake_body[snake_head] - 1;
        break;
    case POS_LEFT:
        new_body = snake_body[snake_head] - 16;
        break;
    case POS_DOWN:
        new_body = snake_body[snake_head] + 1;
        break;
    }

    // 边界检查
    if (new_body / 16 > 15 || new_body % 16 > 7 || new_body % 16 == 8)
    {
        game_over_flag = 1;
        game_state = STATE_GAME_OVER;
        return;
    }

    // 检查自身碰撞
    for (i = 0; i < snake_length; i++)
    {
        unsigned char idx = (snake_head + SNAKE_BODY_MAX - i) % SNAKE_BODY_MAX;
        if (snake_body[idx] == new_body)
        {
            game_over_flag = 1;
            game_state = STATE_GAME_OVER;
            return;
        }
    }

    // 检查是否吃到食物
    if (new_body == food_position)
    {
        score++;
        snake_length++;
        // 增加速度
        if (score % 3 == 0 && speed < 10)
        {
            speed++;
        }
        // 生成新的食物位置
        do
        {
            food_position = timer_rand() % (16 * 8);
        } while (get_shape_type_index(food_position) != TYPE_INDEX_BLOCK);
    }
    else
    {
        // 正常移动，移除蛇尾
        unsigned char tail_idx = (snake_head + SNAKE_BODY_MAX - snake_length + 1) % SNAKE_BODY_MAX;
        snake_body[tail_idx] = 0;
    }

    // 更新蛇身
    snake_head = (snake_head + 1) % SNAKE_BODY_MAX;
    snake_body[snake_head] = new_body;
    last_direction = current_direction;
}

void display_refresh_snake_body()
{
    unsigned char i;
    lcd_clear_screan();

    // 显示蛇身
    for (i = 0; i < snake_length; i++)
    {
        unsigned char idx = (snake_head + SNAKE_BODY_MAX - i) % SNAKE_BODY_MAX;
        unsigned char pos = snake_body[idx];
        unsigned char row = pos % 16; // 行号 (0-7)
        unsigned char col = pos / 16; // 列号 (0-15)
        unsigned char type_index = get_shape_type_index(pos);

        lcd_display_bytes_in_page(row, col * 8, SHAPE_TYPE[type_index], 8);
    }

    // 显示食物
    unsigned char food_row = food_position % 16;
    unsigned char food_col = food_position / 16;
    lcd_display_bytes_in_page(food_row, food_col * 8, SHAPE_TYPE[TYPE_INDEX_FOOT], 8);
}

void display_start_screen()
{
    lcd_clear_screan();
    // 这里可以显示开始画面的文字或图案
    lcd_display_words_in_page(2, 0, "Press START to play", sizeof("Press START to play"), 8, 16);
}

void display_game_over_screen()
{
    lcd_clear_screan();
    // 显示游戏结束画面，包括分数和速度
    lcd_display_words_in_page(1, 0, "Game Over!", sizeof("Game Over!"), 8, 16);
    lcd_display_words_in_page(3, 0, "Score: ", sizeof("Score: "), 8, 16);
    lcd_display_num(3, 32, score / 1000);
    lcd_display_num(3, 37, (score % 1000) / 100);
    lcd_display_num(3, 42, (score % 100) / 10);
    lcd_display_num(3, 47, score % 10);
    lcd_display_words_in_page(5, 0, "Speed: ", sizeof("Speed: "), 8, 16);
    lcd_display_num(5, 32, speed);
}

void timer0_ISR() interrupt 1
{
    if (game_state == STATE_PLAYING)
    {
        timer_count++;
        if (timer_count >= (10 - speed))
        {
            timer_count = 0;
            move_snake();
            display_refresh_snake_body();
        }
    }
}

void main()
{
    uart_init();
    lcd_init();
    timer0_init();
    timer0_isr_on();

    // 初始化蛇
    snake_body[0] = 0x10; // 第0行
    snake_body[1] = 0x11; // 第1行
    snake_body[2] = 0x12;
    snake_body[3] = 0x13;
    snake_body[4] = 0x14;
    snake_body[5] = 0x15;
    snake_head = 5;
    snake_length = 6;

    // 生成初始食物位置
    do
    {
        food_position = timer_rand() % (16 * 8);
    } while (get_shape_type_index(food_position) != TYPE_INDEX_BLOCK);

    while (1)
    {
        unsigned char btn_code = btn_scan();
        switch (game_state)
        {
        case STATE_START:
            display_start_screen();
            if (btn_code == BTN_CODE_START)
            {
                game_state = STATE_PLAYING;
            }
            break;
        case STATE_PLAYING:
            switch (btn_code)
            {
            case BTN_CODE_LEFT:
                if (last_direction != POS_RIGHT)
                    current_direction = POS_LEFT;
                break;
            case BTN_CODE_RIGHT:
                if (last_direction != POS_LEFT)
                    current_direction = POS_RIGHT;
                break;
            case BTN_CODE_UP:
                if (last_direction != POS_DOWN)
                    current_direction = POS_UP;
                break;
            case BTN_CODE_DOWN:
                if (last_direction != POS_UP)
                    current_direction = POS_DOWN;
                break;
            }
            break;
        case STATE_GAME_OVER:
            display_game_over_screen();
            if (btn_code == BTN_CODE_START)
            {
                // 重置游戏
                game_over_flag = 0;
                game_state = STATE_START;
                score = 0;
                speed = 1;
                timer_count = 0;

                // 初始化蛇
                snake_body[0] = 0x10; // 第0行
                snake_body[1] = 0x11; // 第1行
                snake_body[2] = 0x12;
                snake_body[3] = 0x13;
                snake_body[4] = 0x14;
                snake_body[5] = 0x15;
                snake_head = 5;
                snake_length = 6;

                // 生成初始食物位置
                do
                {
                    food_position = timer_rand() % (16 * 8);
                } while (get_shape_type_index(food_position) != TYPE_INDEX_BLOCK);
            }
            break;
        }
    }
}